﻿namespace Lyo.Comm
{
    using System;
    using System.Runtime.InteropServices;

    /// <summary> 结构体 与数组转换  </summary>
    public static class StructHelper
    {

        #region 单个对象

        /// <summary> struct转换为byte[] </summary>
        public static byte[] ToBytes(this object structObj)
        {
            int size = Marshal.SizeOf(structObj);
            IntPtr buffer = Marshal.AllocHGlobal(size);
            try
            {
                Marshal.StructureToPtr(structObj, buffer, false);
                byte[] bytes = new byte[size];
                Marshal.Copy(buffer, bytes, 0, size);
                return bytes;
            }
            finally
            {
                Marshal.FreeHGlobal(buffer);
            }
        }

        /// <summary> byte[]转换为struct </summary>
        public static T FromBytes<T>(this byte[] bytes, int index = 0)
        {
            int size = Marshal.SizeOf(typeof(T));
            IntPtr buffer = Marshal.AllocHGlobal(size);
            try
            {
                Marshal.Copy(bytes, index, buffer, bytes.Length > size ? size : bytes.Length);
                return (T)Marshal.PtrToStructure(buffer, typeof(T));
            }
            finally
            {
                Marshal.FreeHGlobal(buffer);
            }
        }

        public static T FromPtr<T>(IntPtr ptr)
        {
            int size = Marshal.SizeOf(typeof(T));
            byte[] arr = new byte[size];

            try
            {
                Marshal.Copy(ptr, arr, 0, size);
                IntPtr ptr2 = Marshal.UnsafeAddrOfPinnedArrayElement(arr, 0);
                return (T)Marshal.PtrToStructure(ptr2, typeof(T));
            }
            catch
            {
                // 返回一个空实例 
                return System.Activator.CreateInstance<T>();
            }
        }

        #endregion


        #region 对象数组 

        /// <summary> struct[] 转换为byte[] </summary>
        public static byte[] ToBytes(object[] structArr)
        {
            int size = Marshal.SizeOf(structArr[0]);
            int count = structArr.Length;

            IntPtr buffer = Marshal.AllocHGlobal(size);
            try
            {
                byte[] bytes = new byte[size * count];

                for (int i = 0; i < count; i++)
                {

                    Marshal.StructureToPtr(structArr[i], buffer, false);
                    Marshal.Copy(buffer, bytes, i * size, size);
                }
                return bytes;
            }
            finally
            {
                Marshal.FreeHGlobal(buffer);
            }
        }

        /// <summary> byte[]转换为 struct[] </summary>
        public static T[] ArrFromBytes<T>(byte[] bytes, int offset = 0, int count = 0)
        {



            int size = Marshal.SizeOf(typeof(T));

            if (count == 0)
                count = bytes.Length / size;

            IntPtr buffer = Marshal.AllocHGlobal(size);
            try
            {
                T[] arr = new T[count];


                for (int i = 0; i < count; i++)
                {

                    Marshal.Copy(bytes, offset + i * size, buffer, size);
                    arr[i] = (T)Marshal.PtrToStructure(buffer, typeof(T));
                }
                return arr;
            }
            finally
            {
                Marshal.FreeHGlobal(buffer);
            }
        }

        #endregion

        #region 代码有问题

        /// <summary> struct转换为byte[] </summary>
        //public static byte[] ToBytes(object structObj)
        //{
        //    byte[] buff = new byte[Marshal.SizeOf(structObj)];
        //    IntPtr ptr = Marshal.UnsafeAddrOfPinnedArrayElement(buff, 0);
        //    Marshal.StructureToPtr(structObj, ptr, true);
        //    return buff;
        //}

        //public static byte[] toBytes(this  object structObj)
        //{
        //    byte[] buff = new byte[Marshal.SizeOf(structObj)];
        //    IntPtr ptr = Marshal.UnsafeAddrOfPinnedArrayElement(buff, 0);
        //    Marshal.StructureToPtr(structObj, ptr, true);
        //    return buff;
        //}


        ///// <summary> byte[]转换为struct </summary>
        //public static T FromBytes<T>(byte[] bytes) 
        //{
        //    IntPtr ptr = Marshal.UnsafeAddrOfPinnedArrayElement(bytes, 0);
        //    return (T)Marshal.PtrToStructure(ptr, typeof(T) );
        //}


        #endregion


    }
}
